package com.course.redisson.service.RMap;

import com.course.common.enums.Constant;
import com.course.model.entity.redisson.UserOrder;
import com.course.model.mapper.redisson.UserOrderMapper;
import com.course.model.util.CopyUtil;
import com.course.model.util.SnowFlake;
import com.course.redisson.dto.UserOrderDto;
import org.redisson.api.RBlockingDeque;
import org.redisson.api.RDelayedQueue;
import org.redisson.api.RMapCache;
import org.redisson.api.RedissonClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Date;
import java.util.concurrent.TimeUnit;

/**
 * @PROJECT_NAME: course
 * @DESCRIPTION: 商城平台用户订单实战Service层
 * @Author: 涂玄武
 * @DATE: 2021/6/7 10:10
 */
@Service
public class OrderService {

    private static final Logger logger = LoggerFactory.getLogger(OrderService.class);

    private static final SnowFlake SNOWFLAKE = new SnowFlake(2, 3);

    @Resource
    private UserOrderMapper userOrderMapper;

    @Resource
    private RedissonClient redissonClient;

    /**
     * 创建订单-redisson的类延迟队列功能组件-下单时设定一个随机的失效时间(一般是某个业务时间范围内的，如 30-60分钟)
     * 应用场景：用户订单超时未支付自动失效 （Redisson-RMapCache-元素淘汰机制）
     *         实现会员到期前N天提醒:https://blog.csdn.net/weixin_42994251/article/details/108502476?utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromMachineLearnPai2%7Edefault-1.control&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromMachineLearnPai2%7Edefault-1.control
     * @param order
     * @param ttl
     * @return
     */
    public String addOrder(UserOrderDto order, final Long ttl) {
        String orderNo = Constant.OrderType.Item.getType() + SNOWFLAKE.nextId();
        order.setOrderNo(orderNo);
        order.setCreateTime(new Date());
        order.setPayStatus(Constant.OrderPayStatus.UnPay.getCode());
        int res = userOrderMapper.insertSelective(CopyUtil.copy(order, UserOrder.class));
        if (res > 0 && ttl > 0) {
            //TODO:MapCache - 元素的淘汰策略~ 带有元素淘汰（Eviction）机制的映射类允许针对一个映射中每个元素单独设定 有效时间 和 最长闲置时间
            //TODO:无形中提供了一种 “单独失效某个元素Value，而不是整个Key” 的机制:可以通过为某个元素指定存储时间从而决定该数据元素的存活时效，而
            //TODO:不存在所有数据元素共同的Key失效从而导致所有的数据元素都出现丢失的情况
            RMapCache<Integer, String> rMapCache = redissonClient.getMapCache(Constant.RedisMapCacheUserOrder);
            rMapCache.put(order.getId(),orderNo,ttl, TimeUnit.SECONDS);

            /**
             * 参考文章链接：
             * https://blog.csdn.net/weixin_42994251/article/details/108502476?utm_medium=distribute.pc_relevant.
             * none-task-blog-2%7Edefault%7EBlogCommendFromMachineLearnPai2%7Edefault-1.control&depth_1-utm_source
             * =distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromMachineLearnPai2%7Edefault-1.control
             */
//            不推荐使用，只做了解，因需要用到定时器，故不如MapCache好用
//            RBlockingDeque<String> blockingDeque = redissonClient.getBlockingDeque(Constant.RedisMapCacheUserOrder);
//            RDelayedQueue<String> rDelayedQueue = redissonClient.getDelayedQueue(blockingDeque);
//            String value = order.getId() + "_" + orderNo;
//            rDelayedQueue.offer(value,ttl,TimeUnit.SECONDS);

            logger.info("--订单信息进Redisson延迟队列，订单编号：{}，时间为ttl={} 秒",orderNo,ttl);
        }
        return orderNo;
    }
}
